import Vuex from 'vuex';
import Vue from 'vue'
import axios from 'axios'
import Mqtt from 'mqtt'
Vue.use( Vuex )

var mqtt;

/*
 *
 * for monitor protector status , define following field in 
 * protector
 * { 
 *      arm_areas: { 
 *          1: { 
 *              a:     //stamp , alarm stamp
 *              s:             // c(hefang) / b(ufang) / a(larm)
 *          }
 *      }
 *      status: 'b'(bufang) / 'c'(chefang) / 'p'(pending) / 'a'( alarm )
 *      stamp: {stamp}
 *      mac: { 1111111}//not ":" sperator
 *      ip: 
 * }
 * 
 * protector init arm_area by update get status by subscribe "protector/status"
 * 
 * 
 **/

const store = new Vuex.Store({
    state : { 
        shops: { },
        protectors: { },
        alarmLogs: [],
        areas: {},
    },
    actions:{
        pullAlarmLogs( { commit }, { start, limit } ){
            console.log( "pull alarmLogs from ", start );
            axios.get( '/api/v1/security/alarmLogs', { params: { start: Date.now() - (start * 3600 * 1000) }}).then(function( resp ){
                var alarmLogs = resp.data;
                commit( "refreshAlarmLogs",  alarmLogs );
            });
        },
        processAlarm( { commit, state }, { stamp, process_result }){
            axios.get( '/api/v1/security/alarmLogs', { params: { stamp, process_result }}).then( function( data ) { 
                commit( "fixAlarm", { stamp, process_result } );
            });
        }
    },
    mutations: { 
        init( state, init ) { 
            state.protectors = init.protectors;
            state.shops = init.shops;
            state.areas = init.areas;
            state.alarmLogs = init.alarmLogs;
        },
        refreshAlarmLogs( state, alarmLogs ){
            state.alarmLogs = alarmLogs;
        },
        fixAlarm( state, { stamp, process_result }  ){
            for( let i = 0; i < state.alarmLogs.length; i++ ){
                if( state.alarmLogs[i].stamp == stamp  ){
                    Vue.set( state.alarmLogs[i], "process_result", process_result );
                    break;
                }
            }
        },
        updateProtectorStatus( state, { mac, status, stamp } ){
            console.log( 'update protector status',  mac )
            if( state.protectors[mac ]){
                //sometimes, the protector haven't been binded with shop, so ignore the alarm message from filter
                Vue.set( state.protectors[mac], 'status', status );
                if( stamp ){
                    Vue.set( state.protectors[mac], 'stamp', stamp );
                }
                console.log( state.protectors[mac] )
            }
        },

        updateArmAreaStatus( state, { mac, arm_area_idx, status, stamp  }) {
            Vue.set( state.protectors[mac].arm_areas,  arm_area_idx , { s: status, t: stamp } );
        },

        updateQueryStatus( state,  msg ) {
            for( let mac in msg ){
                if( !state.protectors[mac]){
                    continue;
                }

                Vue.set( state.protectors[mac] , 'status', msg[mac].status );
                Vue.set( state.protectors[mac] , 'stamp', msg[mac].stamp );
                for( let idx in msg[mac].arm_areas ){
                    if( !state.protectors[mac].arm_areas[idx]){
                        console.log( '!!!  arm_area_idx: ', idx, ' is not setting  !!!')
                        continue;
                    }
                    if( msg[mac].arm_areas[idx].a )
                        Vue.set( state.protectors[mac].arm_areas[idx], 's', 'a');
                    else 
                        Vue.set( state.protectors[mac].arm_areas[idx], 's', msg[mac].arm_areas[idx].s );
                }
            }
        },

        updateAlarmLogs( state, alarm ){
            if( state.shops[alarm.shopid].arm_areas[alarm.arm_area_idx]){
                //invalid alarmLog, the arm_area_idx is not valid 
                console.log( state.alarmLogs );
                state.shops[alarm.shopid].arm_areas[alarm.arm_area_idx].a = alarm.stamp;
            }
            console.log( state.alarmLogs );
            state.alarmLogs.push( alarm );
        },

        //bufang operation
        setProtector( state, { mac, arm_areas } ){
            //var new_protector =  Object.assign( {}, this.protectors[mac] , {arm_areas: arm_areas})
            //Vue.set( this.protectors, mac, new_protector )
            Vue.set( state.protectors[mac], 'status', "pending");

            var keys = Object.keys( state.shops[state.protectors[mac].shopid].arm_areas );
            //stand for bufang areas 
            var aBufangAreas =[];
            //stand for chefang areas
            var aChefangAreas = [];

            for( let i = 0; i < keys.length; i++ ){
                if( !arm_areas[keys[i]] ) { 
                    aChefangAreas.push( keys[i] );
                    Vue.set( state.protectors[mac].arm_areas[keys[i]], "s",  "c" );
                }
                else {
                    aBufangAreas.push( keys[i]);
                    Vue.set( state.protectors[mac].arm_areas[keys[i]], "s",  "b" );
                }
            }

            console.log( 'setProtector: ');
            console.log( mac , arm_areas , state.protectors[mac]);

            axios.put( "/api/v1/security/operateLog", { mac: mac, operation:{ bufang: aBufangAreas, chefang: aChefangAreas } } ).then( (resp)=>{ 
                console.log( "set protector success ", resp.data );
                return;
            });

            mqtt.publish( 'controller/bufang/' + mac, JSON.stringify( aChefangAreas ), function(){
                console.log("send to device ... ");
            });
        },
        //chefang operation
        cancelProtector( state, { mac } ) {
            Vue.set( state.protectors[mac], 'status', 'pending');
            axios.put( "/api/v1/security/operateLog", { mac: mac, operation:{ chefang: Object.keys( state.protectors[mac].arm_areas )} } ).then( (resp)=>{ 
                console.log( "set protector success ", resp.data );
                return;
            });
            mqtt.publish( "controller/chefang/" + mac, JSON.stringify( ""), function() { 
                console.log( 'chefang ' + mac  + " .... ");
            } )
        }
    }
});

function initState() { 

    var promiseShops = axios.get( '/api/v1/security/shops').catch( function( error ){ 
        console.log(error.response  )
        if( error.response.status == 403 ){
            console.log(' reload ' );
            window.location.href = window.location.origin +'/login.html';
            console.log(window.location );
        }
    });
    var promiseProtectors = axios.get( '/api/v1/security/protectors').catch( function( error ){ 
        console.log( error.response );
        if( error.response.status == 403 ){
            console.log(' reload ' );
            window.location.href = window.location.origin +'/login.html';
            console.log(window.location );
        }
    });
    var promiseMqtt = axios.get( '/api/v1/security/mqtt/serverInfo').catch( function( error){
        console.log( error.response );
        if( error.response.status == 403 ){
            console.log(' reload ' );
            window.location.href = window.location.origin +'/login.html';
            console.log(window.location );
        }
    });
    var promiseAlarmLogs = axios.get( '/api/v1/security/alarmLogs', { params: { start: Date.now() - ( 12 * 3600 * 1000 ) } } ).catch( function( error ){ 
        console.log( error.response );
        if( error.response.status == 403 ){
            console.log(' reload ' );
            window.location.href = window.location.origin +'/login.html';
            console.log(window.location );
        }
    });
    var promiseAreas = axios.get( '/api/v1/security/areas').catch( function( err){ 
        console.log( error.response );
        if( error.response.status == 403 ){ 
            console.log( 'reload');
            window.location.href = window.location.origin +'/login.html';
            console.log(window.location );
        }
    });

    return  Promise.all( [promiseShops, promiseProtectors, promiseMqtt, promiseAlarmLogs, promiseAreas ]).then(
            function ( values  ) {
                console.log( values );
                var shops = values[0].data.shops;
                var protectors = values[1].data.protectors;
                var mqttServer = values[2].data;
                var alarmLogs = values[3].data;
                var areas = values[4].data;

                console.log( 'mqttServer :  ', mqttServer )
    
                mqtt = Mqtt.connect( "ws://" + mqttServer.host + ":" + mqttServer.web_port );
    
                mqtt.on( 'connect', ( ack ) => { 
                    mqtt.subscribe( "monitor/#" )
                    mqtt.subscribe( "webclient/alarmlogs")
                    return true;
                });

                mqtt.on( "message", ( topic, payload, packet  )=> { 
                    var all = topic.split( "/");
                    var prefix = all[0];
                    var type = all[1];
                    var mac = all[2];
                    if( prefix != 'monitor'){ 
                        console.error( "unexpected mqtt topic ", prefix );
                        return ;
                    }

                    var msg = JSON.parse( payload.toString() );
                    console.log( "get mqtt message: ", topic, msg );

                    //it is from filter 
                    if( type == "query"){
                        console.log( "get query ack ... ")
                        //the query ack message
                        if( mac == "all")
                            store.commit( "updateQueryStatus", msg );
                        else 
                            store.commit( "updateQueryStatus", { [mac]: msg } );
                    }
                    //for arm area info 
                    else if( type == "alarmLog"){
                        store.commit( "updateArmAreaStatus", { mac: mac, arm_area_idx: msg.arm_area_idx, status: 'a' , stamp: ( Date.now() / 1000 ) } );
                        store.commit( "updateAlarmLogs", msg );
                    }
                    else if( type == "bypass"){
                        store.commit( "updateArmAreaStatus", { mac: mac, arm_area_idx: msg,  status: 'c'})
                    }
                    else if( type == "notReady"){
                        store.commit( "updateArmAreaStatus", { mac: mac, arm_area_idx: msg,  status: 'c'})
                    }
                    else if( type == "status"){
                        if( msg.type == "alarmed"){
                            store.commit( "updateProtectorStatus", { mac: mac, status: "a", stamp: msg.stamp } );
                        }
                        else if( msg.type == "armed"){
                            store.commit( "updateProtectorStatus", { mac: mac, status: 'b', stamp: msg.stamp } );
                        }
                        else if( msg.type == "disarmed"){
                            store.commit( "updateProtectorStatus", { mac: mac, status: 'c', stamp: msg.stamp } );
                        }
                        else {
                            console.error( "unexpected");
                        }
                    }
                    else{
                        console.error( "unexpected device message  ", topic )
                    }
                });
    
                console.log( 'shops: ', shops, 'protectors: ', protectors )
    
                var state  = { shops: {}, protectors : {}, areas: {}  }
                state.alarmLogs = alarmLogs;

                for( var i = 0; i < shops.length; i++ ) { 
                    state.shops[shops[i].id] = shops[i];
                    //one store have one protector only !!!
                }
    
                for ( var i = 0; i < protectors.length; i++) {
                    protectors[i].mac = protectors[i].mac.replace( /\:/g, "" );
                    state.protectors[ protectors[i].mac.replace(/\:/g, "" ) ] = protectors[i];
                    if( protectors[i].shopid ) { 
                        var shopid = protectors[i].shopid;
                        state.shops[shopid].mac = protectors[i].mac;
                        protectors[i].arm_areas = { };
                        for( let idx in state.shops[shopid].arm_areas){
                            protectors[i].arm_areas[idx] ={ t:null, s: null };
                        }
                    }
                }

                for( let i = 0; i < areas.length; i++ ){
                    state.areas[areas[i].id] = areas[i];
                }

                console.log( 'init state: ', state )
                store.commit( 'init', state )
                mqtt.publish( 'query/all', JSON.stringify( "" ), ()=> { 
                    console.log( 'query all devices status ... ');
                });
            }
        );
}

export { initState, store } 
